package orm

import (
	"context"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/utils"
	env2 "prod/pkg/env"
	"prod/pkg/log"
	"strings"
	"time"
)

// Logger 自定义logger
type Logger struct {
	LogLevel      logger.LogLevel
	env           env2.Type
	skipNormalLog bool
}

// LogMode 日志级别
func (l *Logger) LogMode(level logger.LogLevel) logger.Interface {
	newLogger := *l
	newLogger.LogLevel = level
	return &newLogger
}

// Info Info
func (l Logger) Info(ctx context.Context, msg string, data ...interface{}) {
	_logger := log.FromContext(ctx)
	if l.LogLevel >= logger.Info && !strings.Contains(msg, "replacing callback") {
		_logger.Infof("%s\n[info]"+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
	}
}

// Warn Warn
func (l Logger) Warn(ctx context.Context, msg string, data ...interface{}) {
	_logger := log.FromContext(ctx)
	if l.LogLevel >= logger.Warn {
		_logger.Warnf("%s\n[warn]"+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
	}
}

// Error Error
func (l Logger) Error(ctx context.Context, msg string, data ...interface{}) {
	_logger := log.FromContext(ctx)
	if l.LogLevel >= logger.Error {
		_logger.Warnf("%s\n[error]"+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
	}
}

// Trace 追踪日志
func (l Logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
	canSkip := (err == nil || errors.Is(err, gorm.ErrRecordNotFound)) && l.env == env2.Production
	if canSkip && l.skipNormalLog {
		// 跳过模式，屏蔽一切非报错日志
		return
	}
	if l.LogLevel > 0 {
		elapsed := time.Since(begin)
		sql, rows := fc()
		if canSkip && strings.HasPrefix(sql, "SELECT") {
			// 非跳过模式，允许跳过select语句
			return
		}
		// orm打印日志时去除引号，目前底层引号在日志拼接&sql描述中无实际意义
		log.FromContext(ctx).Infow("sql",
			"body", strings.ReplaceAll(sql, "\"", ""),
			"resp", fmt.Sprintf("Affect %d Rows", rows),
			"error", err, "path", utils.FileWithLineNum(),
			"latency", float64(elapsed.Nanoseconds())/1e6)
	}
}
